#pragma once
/*
    实现异步缓冲区
*/

// 异步：避免写日志过程阻塞（频繁磁盘IO），影响效率
/*
        解决：不让业务线程执行写入磁盘操作（落地）；先写入缓冲区，由异步线程进行写入磁盘
    1. 缓冲区涉及多线程读写，所以需要线程安全
    1.1 使用一个队列缓存日志消息（逐条处理）【不能有频繁开辟与释放内存行为】
                                         基于环形队列实现生产者消费者模型】
        生产与生产互斥、生产与消费互斥
    1.2 每条消息进入缓冲区都会进行锁竞争【严重】
        设计双缓冲区：  降低了生产与消费之间的冲突
        业务线程--->>>任务写入缓冲区<<====>>任务处理缓冲区--->>>异步工作线程
                            【写满后直接交换缓冲区】
        /////单个缓冲区设计
            //原本需要先给每一条日志构造LogMsg对象 再将对象存入缓冲区
            //解决：主线程只需要将格式化后的字符串存入缓冲区即可，省去了大量构造LogMsg对象消耗
            //1. 使用vector进行环形队列管理
            //2. 需要  当前可写入位置指针 和 当前可读取位置指针
            //3. 写缓冲区方法、读缓冲区方法
                        （利用可读起始位置接口 与 可读大小接口 与 偏移读写指针两接口）
                 、交换缓冲区指针方法、初始化缓冲区方法
*/

#include "1_util.hpp"
#include <vector>
#include <assert.h>

namespace senlog
{
#define DEFAULT_BUUFFER_SIZE 1024 * 1024 * 10   // 10M大小缓冲区
#define THRESHOLD_BUFFER_SIZE 1024 * 1024 * 80  //设置扩容阈值：当前缓冲区小于阈值 翻倍增长；大于阈值 线性增长。
#define INCREMENT_BUFFER_SIZE 1024 *1024 * 10   //增量  10M
    class Buffer
    {
    private:
        std::vector<char> _buffer;
        size_t _reader_idx; // 当前可读指针（索引）
        size_t _writer_idx; // 当前可写指针
    private:
        void ensureEnoughSize(size_t len)
        {
            if(writeableSize() > len)   return;

            size_t new_size = 0;
            if(_buffer.size() < THRESHOLD_BUFFER_SIZE) 
                new_size = _buffer.size() * 2; //防止扩容后仍然 < len；那么直接在后面额外 + len;
            else
                new_size = _buffer.size() + INCREMENT_BUFFER_SIZE;

            _buffer.resize(new_size);
        }
    public:
        Buffer()
            :_buffer(DEFAULT_BUUFFER_SIZE)
            ,_reader_idx(0)
            ,_writer_idx(0)
        {}
        void push(const char *data, size_t len) // 写数据
        {
            //缓冲区剩余空间不够 【扩容  |  阻塞】
            ensureEnoughSize(len);              //扩容

            //if(writeableSize() < len)   return; //阻塞 

            std::copy(data, data+len, &_buffer[_writer_idx]);
            shiftWriteIdx(len);
        }
        const char *readableBegin() // 返回可读字符串的 起始地址
        {
            return &_buffer[_reader_idx];
        }
        size_t readableSize() // 返回可读字符串的 长度
        {
            // 非环形数组
            return _writer_idx - _reader_idx;
        }
        size_t writeableSize() // 当前缓冲区剩余空间大小【仅针对固定大小缓冲区】
        {
            return (_buffer.size() - _writer_idx);
        }
        /////将读写指针向后移动len
        void shiftWriteIdx(size_t len) 
        {
            assert(len + _writer_idx <= _buffer.size());
            _writer_idx += len;
        }
        void shiftReadIdx(size_t len) 
        {
            assert(len <= readableSize());
            _reader_idx += len;
        }

        //////重置缓冲区
        void resetBuffer()
        {
            _reader_idx = _writer_idx = 0;
        }
        /////交换缓冲区
        void swapBuffer(Buffer& buffer)
        {
            _buffer.swap(buffer._buffer);
            std::swap(_reader_idx, buffer._reader_idx);
            std::swap(_writer_idx, buffer._writer_idx);
        }
        /////缓冲区为空 不需要交换
        bool empty()
        {
            return _reader_idx == _writer_idx;
        }
    };
};

